package com.digua.base.socket

import android.os.Handler
import android.os.Looper
import com.digua.base.socket.request.Request
import com.digua.base.socket.response.ErrorResponse
import com.digua.base.util.LogUtil
import java.util.ArrayDeque
import java.util.Queue

class WebSocketEngine {

    private var mOptionThread: OptionThread? = null

    constructor() {
        mOptionThread = OptionThread()
        mOptionThread?.start()
    }

    fun sendRequest(webSocket: WebSocketWrapper?, request: Request<*>?, listener: SocketWrapperListener) {
        if (mOptionThread?.mHandler == null) {
            listener.onSendDataError(request, ErrorResponse.ERROR_UN_INIT, null)
        } else {
            val runnable = ReRunnable.obtain()
            runnable.apply {
                this.type = 0
                this.request = request
                this.webSocketWrapper = webSocket
                mOptionThread?.mHandler?.post(this)
            }
        }
    }

    fun connect(webSocket: WebSocketWrapper?, listener: SocketWrapperListener) {
        if (mOptionThread?.mHandler == null) {
            listener.onConnectFailed(Exception("WebSocketEngine not start!"))
        } else {
            val runnable = ReRunnable.obtain()
            runnable.apply {
                this.type = 1
                this.webSocketWrapper = webSocket
                mOptionThread?.mHandler?.post(this)
            }
        }
    }

    fun disConnect(webSocket: WebSocketWrapper?, listener: SocketWrapperListener?) {
        if (mOptionThread?.mHandler != null) {
            val runnable = ReRunnable.obtain()
            runnable.apply {
                this.type = 2
                this.webSocketWrapper = webSocket
                mOptionThread?.mHandler?.post(this)
            }
        } else {
            LogUtil.e("WebSocketEngine not start!")
        }
    }

    fun destroyWebSocket(webSocket: WebSocketWrapper?) {
        if (mOptionThread?.mHandler != null) {
            ReRunnable.obtain().apply {
                this.type = 3
                this.webSocketWrapper = webSocket
                mOptionThread?.mHandler?.post(this)
            }
        } else {
            LogUtil.e("WebSocketEngine not start!")
        }
    }

    fun destroy() = mOptionThread?.mHandler?.sendEmptyMessage(OptionHandler.QUIT)

    private class OptionThread : Thread() {
        var mHandler: OptionHandler? = null
        override fun run() {
            super.run()
            Looper.prepare()
            mHandler = OptionHandler()
            Looper.loop()
        }
    }

    private class OptionHandler : Handler() {
        companion object {
            const val QUIT = 1
        }
    }

    private class ReRunnable : Runnable {
        /**
         * 0-发送数据；
         * 1-链接；
         * 2-断开链接；
         * 3-销毁 WebSocketWrapper 对象。
         */
        var type = 0
        var webSocketWrapper: WebSocketWrapper? = null
        var request: Request<*>? = null
        override fun run() {
            try {
                if (webSocketWrapper == null) return
                if (type == 0 && request == null) return
                webSocketWrapper?.apply {
                    when (type) {
                        0 -> send(request)
                        1 -> reconnect()
                        2 -> disConnect()
                        3 -> destroy()
                    }
                }
            } finally {
                webSocketWrapper = null
                request = null
                release()
            }
        }

        fun release() = POOL.offer(this)

        companion object {
            private val POOL: Queue<ReRunnable> = ArrayDeque(10)
            fun obtain() = POOL.poll() ?: ReRunnable()
        }
    }
}